#include <graphics.h>  // EasyX
#include <conio.h>
#include <fstream>
#include <ctime>
#include <cstdio>

// 游戏常量定义
#define WIDTH 20        // 棋盘宽度（格子数）
#define HEIGHT 20       // 棋盘高度（格子数）
#define CELL_SIZE 30    // 每个格子大小（像素）
#define WALL_THICKNESS 3 // 墙壁厚度（像素）
// 窗口宽度
#define WINDOW_WIDTH CELL_SIZE * (WIDTH + 6) + 30  
#define WINDOW_HEIGHT CELL_SIZE * (HEIGHT+2) + 30    
// 颜色定义（使用 RGB 十六进制增强可读性）
#define COLOR_WALL 0xA9A9A9      // 墙壁颜色（灰色）
#define COLOR_SNAKE_HEAD 0x00BFFF  // 蛇头（天蓝色）
#define COLOR_SNAKE_BODY 0x00FF7F  // 蛇身（绿色）
#define COLOR_FOOD 0xFF6464       // 食物（红色）
#define COLOR_BG 0xFAFAD2         // 背景（米黄色）
#define COLOR_TEXT 0x323232       // 文本颜色（深灰）

// 蛇的结构体定义
struct Snake {
    int x[WIDTH * HEIGHT];  // 蛇身 x 坐标数组（最大长度为棋盘面积）
    int y[WIDTH * HEIGHT];  // 蛇身 y 坐标数组
    int length;             // 当前长度
    int direction;          // 移动方向（1:上，2:下，3:左，4:右）
};

// 全局变量
struct Snake snake;               // 蛇对象
int foodX, foodY;          // 食物坐标
int score = 0;             // 当前分数
int highScore = 0;         // 历史最高分
int gameSpeed = 300;       // 游戏速度（毫秒/帧）
bool isGameRunning = true; // 游戏运行状态
bool isPaused = false;     // 游戏暂停状态
clock_t lastUpdateTime = 0; // 上次更新时间

// 函数前置声明
void initGame();           // 初始化游戏数据
void drawGame();           // 绘制游戏画面
bool generateFood();       // 生成新食物（避免与蛇身重叠）
void handleInput();        // 处理用户输入
bool checkCollision();     // 检测碰撞（墙壁或自身）
void showDifficulty();     // 难度选择界面
void showGameOver();       // 游戏结束界面
void updateGame();         // 更新游戏逻辑

// 主函数：程序入口
int main() {
    // 初始化图形窗口（检查是否成功）
    if (initgraph(WINDOW_WIDTH, WINDOW_HEIGHT) == NULL) {
        printf("错误：图形窗口初始化失败！\n");
        return 1;
    }
    setaspectratio(1, 1);  // 保持格子为正方形

    // 显示难度选择界面
    showDifficulty();

    // 初始化游戏数据
    initGame();

    // 游戏主循环
    while (isGameRunning) {
        // 处理输入（即时响应）
        handleInput();

        // 暂停状态下不更新游戏逻辑
        if (isPaused) {
            Sleep(50);
            continue;
        }

        // 控制游戏更新频率
        clock_t currentTime = clock();
        if (currentTime - lastUpdateTime >= gameSpeed) {
            updateGame();
            lastUpdateTime = currentTime;
        }

        // 绘制游戏画面
        drawGame();
        FlushBatchDraw();   // 双缓冲绘制（避免画面闪烁）

        // 降低CPU使用率
        Sleep(10);
    }

    closegraph();  // 关闭图形环境
    return 0;
}

// 初始化游戏数据（蛇、食物、最高分）
void initGame() {
    // 初始化蛇（初始长度3，居中向右）
    snake.length = 3;
    snake.x[0] = WIDTH / 2;
    snake.y[0] = HEIGHT / 2;
    for (int i = 1; i < snake.length; i++) {
        snake.x[i] = snake.x[i - 1] - 1;  // 初始向左延伸（修正原代码中的错误）
        snake.y[i] = snake.y[i - 1];
    }
    snake.direction = 4;  // 初始方向：右

    // 生成初始食物（随机位置）
    srand((unsigned)time(NULL));  // 设置随机数种子
    if (!generateFood()) {
        printf("错误：无法生成食物！\n");
        isGameRunning = false;
    }

    // 读取历史最高分（从文件）
    FILE* scoreFile = fopen("score.ini", "r");
    if (scoreFile != NULL) {
        fscanf(scoreFile, "%d", &highScore);
        fclose(scoreFile);
    }
    else {
        highScore = 0;  // 文件不存在则默认0分
    }

    // 初始化时间
    lastUpdateTime = clock();
}

// 绘制游戏画面（棋盘、蛇、食物、信息面板）
void drawGame() {
    setbkcolor(COLOR_BG);  // 设置背景色
    cleardevice();         // 清空画面

    // 绘制棋盘边框（墙壁）
    setlinecolor(COLOR_WALL);
    rectangle(
        CELL_SIZE, CELL_SIZE,  // 左上角坐标
        CELL_SIZE * (WIDTH + 1), CELL_SIZE * (HEIGHT + 1)  // 右下角坐标
    );

    // 绘制蛇身（蛇头用特殊颜色）
    for (int i = 0; i < snake.length; i++) {
        if (i == 0) {  // 蛇头
            setfillcolor(COLOR_SNAKE_HEAD);
        }
        else {       // 蛇身
            setfillcolor(COLOR_SNAKE_BODY);
        }
        // 绘制蛇身方块（坐标转换为像素位置）
        solidrectangle(
            CELL_SIZE * snake.x[i], CELL_SIZE * snake.y[i],
            CELL_SIZE * (snake.x[i] + 1), CELL_SIZE * (snake.y[i] + 1)
        );
    }

    // 绘制食物（圆形）
    setfillcolor(COLOR_FOOD);
    fillcircle(
        CELL_SIZE * (foodX + 0.5),  // 圆心 x 坐标（格子中心）
        CELL_SIZE * (foodY + 0.5),  // 圆心 y 坐标
        CELL_SIZE / 2 - 2           // 半径（略小于格子）
    );

    // 绘制信息面板（分数、最高分、难度）
    settextcolor(COLOR_TEXT);      // 设置文本颜色
    setbkmode(TRANSPARENT);        // 文本背景透明
    settextstyle(24, 0, "微软雅黑");  // 设置字体（高度24px，无宽度限制）

    char scoreText[20];
    sprintf(scoreText, "当前分数: %d", score);
    outtextxy(CELL_SIZE * (WIDTH + 2), CELL_SIZE * 2, scoreText);

    char highScoreText[20];
    sprintf(highScoreText, "最高分数: %d", highScore);
    outtextxy(CELL_SIZE * (WIDTH + 2), CELL_SIZE * 4, highScoreText);

    char difficultyText[20];
    const char* difficulty =
        (gameSpeed == 400) ? "简单" :
        (gameSpeed == 250) ? "中等" : "困难";
    sprintf(difficultyText, "难度: %s", difficulty);
    outtextxy(CELL_SIZE * (WIDTH + 2), CELL_SIZE * 6, difficultyText);

    // 显示暂停信息（如果暂停）
    if (isPaused) {
        settextcolor(0xFF0000);  // 红色
        settextstyle(36, 0, "微软雅黑");
        outtextxy(CELL_SIZE * 3, CELL_SIZE * 10, "游戏暂停");
        outtextxy(CELL_SIZE * 3, CELL_SIZE * 14, "按 P 继续");
    }
}

// 生成新食物（避免与蛇身重叠）
bool generateFood() {
    // 创建一个可用位置列表
    bool availablePositions[WIDTH + 1][HEIGHT + 1] = { false };
    for (int x = 1; x <= WIDTH; x++) {
        for (int y = 1; y <= HEIGHT; y++) {
            availablePositions[x][y] = true;
        }
    }

    // 标记蛇身占据的位置
    for (int i = 0; i < snake.length; i++) {
        availablePositions[snake.x[i]][snake.y[i]] = false;
    }

    // 收集所有可用位置
    int availableCount = 0;
    int availableCells[WIDTH * HEIGHT][2];

    for (int x = 1; x <= WIDTH; x++) {
        for (int y = 1; y <= HEIGHT; y++) {
            if (availablePositions[x][y]) {
                availableCells[availableCount][0] = x;
                availableCells[availableCount][1] = y;
                availableCount++;
            }
        }
    }

    // 如果没有可用位置（蛇占满整个棋盘）
    if (availableCount == 0) {
        return false;
    }

    // 从可用位置中随机选择一个
    int randomIndex = rand() % availableCount;
    foodX = availableCells[randomIndex][0];
    foodY = availableCells[randomIndex][1];

    return true;
}

// 处理用户输入（方向键、难度切换、退出）
void handleInput() {
    if (_kbhit()) {  // 检测是否有按键
        int key = _getch();  // 获取按键码

        // 方向键处理（上、下、左、右）
        switch (key) {
        case 72:  // 上箭头（键码72）
            if (snake.direction != 2 && !isPaused) snake.direction = 1;  // 不能反向移动
            break;
        case 80:  // 下箭头（键码80）
            if (snake.direction != 1 && !isPaused) snake.direction = 2;
            break;
        case 75:  // 左箭头（键码75）
            if (snake.direction != 4 && !isPaused) snake.direction = 3;
            break;
        case 77:  // 右箭头（键码77）
            if (snake.direction != 3 && !isPaused) snake.direction = 4;
            break;

            // 难度切换（1:简单，2:中等，3:困难）
        case '1': gameSpeed = 400; break;
        case '2': gameSpeed = 250; break;
        case '3': gameSpeed = 100; break;

            // 暂停/继续游戏
        case 'p':
            isPaused = !isPaused;
            break;

            // ESC 键退出游戏
        case 27:  // ESC 键码（27）
            isGameRunning = false;
            break;
        }
    }
}

// 检测碰撞（墙壁或自身）
bool checkCollision() {
    // 检测墙壁碰撞（蛇头超出棋盘范围）
    if (snake.x[0] < 1 || snake.x[0] > WIDTH ||
        snake.y[0] < 1 || snake.y[0] > HEIGHT) {
        return true;
    }

    // 检测自身碰撞（蛇头与蛇身重叠）
    for (int i = 1; i < snake.length; i++) {
        if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) {
            return true;
        }
    }

    return false;
}

// 难度选择界面（游戏开始前）
void showDifficulty() {
    setbkcolor(COLOR_BG);
    cleardevice();

    // 标题文字
    settextcolor(COLOR_TEXT);
    settextstyle(36, 0, "微软雅黑");
    outtextxy(CELL_SIZE * 2, CELL_SIZE * 4, "选择难度");

    // 选项文字
    settextstyle(24, 0, "微软雅黑");
    outtextxy(CELL_SIZE * 2, CELL_SIZE * 8, "1. 简单 (400ms/步)");
    outtextxy(CELL_SIZE * 2, CELL_SIZE * 10, "2. 中等 (250ms/步)");
    outtextxy(CELL_SIZE * 2, CELL_SIZE * 12, "3. 困难 (100ms/步)");
    outtextxy(CELL_SIZE * 2, CELL_SIZE * 16, "按对应数字键开始...");

    // 等待用户选择难度
    bool isSelected = false;
    while (!isSelected) {
        if (_kbhit()) {
            int key = _getch();
            if (key == '1' || key == '2' || key == '3') {
                switch (key) {
                case '1': gameSpeed = 400; break;
                case '2': gameSpeed = 250; break;
                case '3': gameSpeed = 100; break;
                }
                isSelected = true;  // 选择成功，退出循环
            }
        }
        Sleep(50);  // 降低 CPU 占用
    }
}

// 游戏结束界面（显示分数、新纪录、重新开始提示）
void showGameOver() {
    setbkcolor(COLOR_BG);
    cleardevice();

    // 大标题（红色）
    settextcolor(0xFF0000);  // 红色
    settextstyle(48, 0, "微软雅黑");
    outtextxy(CELL_SIZE * 3, CELL_SIZE * 6, "游戏结束！");

    // 当前分数
    settextcolor(COLOR_TEXT);
    settextstyle(24, 0, "微软雅黑");
    char scoreText[20];
    sprintf(scoreText, "当前分数: %d", score);
    outtextxy(CELL_SIZE * 3, CELL_SIZE * 12, scoreText);

    // 历史最高分（如果破纪录则保存）
    if (score > highScore) {
        highScore = score;
        FILE* scoreFile = fopen("score.ini", "w");
        if (scoreFile != NULL) {
            fprintf(scoreFile, "%d", highScore);
            fclose(scoreFile);
        }
        outtextxy(CELL_SIZE * 3, CELL_SIZE * 14, "新纪录！");
    }

    // 重新开始提示
    outtextxy(CELL_SIZE * 3, CELL_SIZE * 16, "按任意键重新开始");
    outtextxy(CELL_SIZE * 3, CELL_SIZE * 18, "按 ESC 退出游戏");

    // 等待用户输入（重新开始或退出）
    while (true) {
        if (_kbhit()) {
            int key = _getch();
            if (key == 27) {  // ESC 退出
                isGameRunning = false;
                break;
            }
            else {         // 其他键重新开始
                score = 0;    // 重置分数
                initGame();    // 重新初始化游戏
                isGameRunning = true;
                break;
            }
        }
        Sleep(50);
    }
}

// 更新游戏逻辑
void updateGame() {
    // 如果游戏暂停则不更新
    if (isPaused) return;

    // 移动蛇身（从尾部到头部依次更新坐标）
    for (int i = snake.length - 1; i > 0; i--) {
        snake.x[i] = snake.x[i - 1];
        snake.y[i] = snake.y[i - 1];
    }

    // 根据方向更新蛇头坐标
    switch (snake.direction) {
    case 1: snake.y[0]--; break;  // 上
    case 2: snake.y[0]++; break;  // 下
    case 3: snake.x[0]--; break;  // 左
    case 4: snake.x[0]++; break;  // 右
    }

    // 检测是否吃到食物
    if (snake.x[0] == foodX && snake.y[0] == foodY) {
        snake.length++;
        score += 10;
        if (!generateFood()) {
            // 无法生成食物，游戏胜利结束
            isPaused = true;
            settextcolor(0x008000);  // 绿色
            settextstyle(48, 0, "微软雅黑");
            outtextxy(CELL_SIZE * 3, CELL_SIZE * 6, "恭喜你获胜！");
            outtextxy(CELL_SIZE * 3, CELL_SIZE * 12, "按任意键重新开始");
            outtextxy(CELL_SIZE * 3, CELL_SIZE * 14, "按 ESC 退出游戏");

            // 等待用户输入
            while (true) {
                if (_kbhit()) {
                    int key = _getch();
                    if (key == 27) {  // ESC 退出
                        isGameRunning = false;
                        break;
                    }
                    else {         // 其他键重新开始
                        score = 0;    // 重置分数
                        initGame();    // 重新初始化游戏
                        isPaused = false;
                        break;
                    }
                }
                Sleep(50);
            }
        }
    }

    // 检测碰撞（游戏结束）
    if (checkCollision()) {
        showGameOver();
    }
}